﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UvsChess;

namespace StudentAI
{
    public class MoveGeneration
    {
        static public List<ChessMove> getAllMoves( ChessBoard board, ChessColor color ) {
            List<ChessMove> moves = new List<ChessMove>();
            ChessLocation kingLocation = MoveValidation.findKing(board, color);
            for (int y = 0; y < ChessBoard.NumberOfRows; y++) {
                for (int x = 0; x < ChessBoard.NumberOfColumns; x++) {
                    ChessPiece fromPiece = board[x, y];
                    ChessLocation fromLocation = new ChessLocation(x,y);
                    if (MoveValidation.SameColor(fromPiece, color))
                    {
                        switch (fromPiece)
                        {
                            case ChessPiece.Empty:
                                //Do Nothing, Shouldn't get here
                                break;
                            case ChessPiece.BlackBishop:
                            case ChessPiece.WhiteBishop:
                                moves.InsertRange(moves.Count(), generateBishopMoves(board, fromLocation, color, kingLocation));
                                break;
                            case ChessPiece.BlackKing:
                            case ChessPiece.WhiteKing:
                                moves.InsertRange(moves.Count(), generateKingMoves(board, fromLocation, color));
                                break;
                            case ChessPiece.BlackKnight:
                            case ChessPiece.WhiteKnight:
                                moves.InsertRange(moves.Count(), generateKnightMoves(board, fromLocation, color, kingLocation));
                                break;
                            case ChessPiece.BlackPawn:
                            case ChessPiece.WhitePawn:
                                moves.InsertRange(moves.Count(), generatePawnMoves(board, fromLocation, color, kingLocation));
                                break;
                            case ChessPiece.BlackQueen:
                            case ChessPiece.WhiteQueen:
                                moves.InsertRange(moves.Count(), generateQueenMoves(board, fromLocation, color, kingLocation));
                                break;
                            case ChessPiece.BlackRook:
                            case ChessPiece.WhiteRook:
                                moves.InsertRange(moves.Count(), generateRookMoves(board, fromLocation, color, kingLocation));
                                break;
                            default:
                                //Do Nothing, Shouldn't get here
                                break;
                        }
                    }
                    else //If not same color
                    {
                        //Do Nothing
                    }
                }
            }//End Board Loop
            return moves;
        }


        static public bool hasAnyMove(ChessBoard board, ChessColor color)
        {
            ChessLocation kingLocation = MoveValidation.findKing(board, color);
            for (int y = 0; y < ChessBoard.NumberOfRows; y++)
            {
                for (int x = 0; x < ChessBoard.NumberOfColumns; x++)
                {
                    ChessPiece fromPiece = board[x, y];
                    ChessLocation fromLocation = new ChessLocation(x, y);
                    if (MoveValidation.SameColor(fromPiece, color))
                    {
                        switch (fromPiece)
                        {
                            case ChessPiece.Empty:
                                //Do Nothing, Shouldn't get here
                                break;
                            case ChessPiece.BlackBishop:
                            case ChessPiece.WhiteBishop:
                                if (generateBishopMoves(board, fromLocation, color, kingLocation).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackKing:
                            case ChessPiece.WhiteKing:
                                if (generateKingMoves(board, fromLocation, color).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackKnight:
                            case ChessPiece.WhiteKnight:
                                if (generateKnightMoves(board, fromLocation, color, kingLocation).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackPawn:
                            case ChessPiece.WhitePawn:
                                if (generatePawnMoves(board, fromLocation, color, kingLocation).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackQueen:
                            case ChessPiece.WhiteQueen:
                                if (generateQueenMoves(board, fromLocation, color, kingLocation).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackRook:
                            case ChessPiece.WhiteRook:
                                if (generateRookMoves(board, fromLocation, color, kingLocation).Count > 0)
                                    return true;
                                break;
                            default:
                                //Do Nothing, Shouldn't get here
                                break;
                        }
                    }
                    else //If not same color
                    {
                        //Do Nothing
                    }
                }
            }//End Board Loop
            return false;
        }
        static public List<ChessMove> generatePawnMoves(ChessBoard board, ChessLocation pawnLocation, ChessColor color, ChessLocation kingLocation) 
        {
            List<ChessMove> pawnMoves = new List<ChessMove>();
            ChessLocation to;
            ChessMove move;
            ChessBoard newBoard;

            int startY;
            int forward;
            if (color == ChessColor.Black)
            {
                startY = 1;
                forward = 1;
            }
            else //White
            {
                startY = 6;
                forward = -1;
            }
            //If space ahead is empty, add forward move to list
            to = new ChessLocation(pawnLocation.X, pawnLocation.Y + forward);
            if (board[to] == ChessPiece.Empty) 
            { 
                move = new ChessMove(pawnLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if( !MoveValidation.kingInCheck(newBoard, kingLocation, color) )
                    pawnMoves.Add(move);
            }
            //If both spaces ahead are emtpy, and pawn in starting position, forward*2 to list
            to = new ChessLocation(pawnLocation.X, (pawnLocation.Y + forward * 2));
            if (pawnLocation.Y == startY &&
                board[pawnLocation.X, (pawnLocation.Y + forward)] == ChessPiece.Empty &&
                board[to] == ChessPiece.Empty) 
            {
                move = new ChessMove(pawnLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                pawnMoves.Add(move);
            }
            //If not going off of board, and diagonal is an enemy piece, add Pawn Take move to list
            to = new ChessLocation(pawnLocation.X - 1, pawnLocation.Y + forward);
            if (pawnLocation.X - 1 >= 0 &&
                isEnemyPiece(board[to], color)) 
            {
                move = new ChessMove(pawnLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                pawnMoves.Add(move);
            }
            //If not going off of board, and diagonal is an enemy piece, add Pawn Take move to list
            to = new ChessLocation(pawnLocation.X + 1, pawnLocation.Y + forward);
            if (pawnLocation.X + 1 <= 7 &&
                isEnemyPiece(board[to], color))
            {
                move = new ChessMove(pawnLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                pawnMoves.Add(move);
            }
            return pawnMoves;
        }

        static public List<ChessMove> generateRookMoves(ChessBoard board, ChessLocation rookLocation, ChessColor color, ChessLocation kingLocation)
        {
            List<ChessMove> rookMoves = new List<ChessMove>();
            ChessPiece currentPiece;
            ChessLocation to;
            ChessMove move;
            ChessBoard newBoard;
            //Go in 4 directions
            //break loop if end of board or not empty
            //x+
            for (int x = rookLocation.X + 1; x <= 7 ; ++x) 
            {
                to = new ChessLocation(x, rookLocation.Y);
                currentPiece = board[to];
                //If empty or enemy
                if (!MoveValidation.SameColor(currentPiece, color))
                {
                    move = new ChessMove(rookLocation, to);
                    newBoard = board.Clone();
                    newBoard.MakeMove(move);
                    if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                        rookMoves.Add(move);
                    //If enemy
                    if (currentPiece != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(currentPiece, color))
                    break;
            }
            //x-
            for (int x = rookLocation.X - 1; x >= 0 ; --x)
            {
                to = new ChessLocation(x, rookLocation.Y);
                currentPiece = board[to];
                //If empty or enemy
                if (!MoveValidation.SameColor(currentPiece, color))
                {
                    move = new ChessMove(rookLocation, to);
                    newBoard = board.Clone();
                    newBoard.MakeMove(move);
                    if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                        rookMoves.Add(move);
                    //If enemy
                    if (currentPiece != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(currentPiece, color))
                    break;
                
            }
            //y+
            for (int y = rookLocation.Y + 1; y <= 7; ++y)
            {
                to = new ChessLocation(rookLocation.X, y);
                currentPiece = board[to];
                //If empty or enemy
                if (!MoveValidation.SameColor(currentPiece, color))
                {
                    move = new ChessMove(rookLocation, to);
                    newBoard = board.Clone();
                    newBoard.MakeMove(move);
                    if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                        rookMoves.Add(move);
                    //If enemy
                    if (currentPiece != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(currentPiece, color))
                    break;
                
            }
            //y-
            for (int y = rookLocation.Y - 1; y >= 0; --y)
            {
                to = new ChessLocation(rookLocation.X, y);

                currentPiece = board[to];
                //If empty or enemy
                if (!MoveValidation.SameColor(currentPiece, color))
                {
                    move = new ChessMove(rookLocation, to);
                    newBoard = board.Clone();
                    newBoard.MakeMove(move);
                    if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                        rookMoves.Add(move);
                    //If enemy
                    if (currentPiece != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(currentPiece, color))
                    break;
                
            }
            return rookMoves;
        }

        static public List<ChessMove> generateBishopMoves(ChessBoard board, ChessLocation bishopLocation, ChessColor color, ChessLocation kingLocation)
        {
            List<ChessMove> bishopMoves = new List<ChessMove>();
            ChessLocation to;
            ChessMove move;
            ChessBoard newBoard;
            //Go in 4 directions
            int x, y;
            //x+ y+
            x = bishopLocation.X + 1;
            y = bishopLocation.Y + 1;
            for (; (x < ChessBoard.NumberOfColumns &&
                    y < ChessBoard.NumberOfRows); ++x, ++y) {
                        to = new ChessLocation(x, y);
                        if (board[to] == ChessPiece.Empty) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                        }
                        else if (!MoveValidation.SameColor(board[to], color)) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                            break;
                        }
                        else
                        {
                            break;
                        }
            }
            //x+ y-
            x = bishopLocation.X + 1;
            y = bishopLocation.Y - 1;
            for (; (x < ChessBoard.NumberOfColumns &&
                    y >= 0); ++x, --y) {
                        to = new ChessLocation(x, y);
                        if (board[to] == ChessPiece.Empty ) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                        }
                        else if (!MoveValidation.SameColor(board[to], color)) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                            break;
                        }
                        else {
                            break;
                        }
            }
            //x- y+
            x = bishopLocation.X - 1;
            y = bishopLocation.Y + 1;
            for (; (x >= 0 &&
                    y < ChessBoard.NumberOfRows); --x, ++y) {
                        to = new ChessLocation(x, y);
                        if (board[to] == ChessPiece.Empty ) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                        }
                        else if (!MoveValidation.SameColor(board[to], color)) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                            break;
                        }
                        else
                        {
                            break;
                        }
            }
            //x- y-
            x = bishopLocation.X - 1;
            y = bishopLocation.Y - 1;
            for (; (x >= 0 &&
                    y >= 0); --x, --y) {
                        to = new ChessLocation(x, y);
                        if (board[to] == ChessPiece.Empty) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                        }
                        else if (!MoveValidation.SameColor(board[to], color)) {
                            move = new ChessMove(bishopLocation, to);
                            newBoard = board.Clone();
                            newBoard.MakeMove(move);
                            if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                                bishopMoves.Add(move);
                            break;
                        }
                        else
                        {
                            break;
                        }
            }
            return bishopMoves;
        }

        static public List<ChessMove> generateKnightMoves(ChessBoard board, ChessLocation knightLocation, ChessColor color, ChessLocation kingLocation)
        {
            List<ChessMove> knightMoves = new List<ChessMove>();
            ChessLocation to;
            ChessMove move;
            ChessBoard newBoard;
            int x, y;
            //Test 8 directions, make sure empty or enemy (!same)
            //Y + 2, X + 1
            x = knightLocation.X + 1;
            y = knightLocation.Y + 2;
            to = new ChessLocation(x, y);
            if (y <= 7 && x <= 7 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            //Y + 2, X - 1
            x = knightLocation.X - 1;
            y = knightLocation.Y + 2;
            to = new ChessLocation(x, y);
            if (y <= 7 && x >= 0 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            //Y - 2, X + 1
            x = knightLocation.X + 1;
            y = knightLocation.Y - 2;
            to = new ChessLocation(x, y);
            if (y >= 0 && x <= 7 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            //Y - 2, X - 1
            x = knightLocation.X - 1;
            y = knightLocation.Y - 2;
            to = new ChessLocation(x, y);
            if ( y >= 0 && x >= 0 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            //X + 2, Y + 1
            x = knightLocation.X + 2;
            y = knightLocation.Y + 1;
            to = new ChessLocation(x, y);
            if ( y <= 7 && x <= 7 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            //X + 2, Y - 1
            x = knightLocation.X + 2;
            y = knightLocation.Y - 1;
            to = new ChessLocation(x, y);
            if ( y >= 0 && x <= 7 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            //X - 2, Y + 1
            x = knightLocation.X - 2;
            y = knightLocation.Y + 1;
            to = new ChessLocation(x, y);
            if ( y <= 7 && x >= 0 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            //X - 2, Y - 1
            x = knightLocation.X - 2;
            y = knightLocation.Y - 1;
            to = new ChessLocation(x, y);
            if ( y >= 0 && x >= 0 && !MoveValidation.SameColor(board[to], color))
            {
                move = new ChessMove(knightLocation, to);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, kingLocation, color))
                    knightMoves.Add(move);
            }
            return knightMoves;
        }

        static public List<ChessMove> generateQueenMoves(ChessBoard board, ChessLocation queenLocation, ChessColor color, ChessLocation kingLocation)
        {
            List<ChessMove> queenMoves = new List<ChessMove>();
            queenMoves.InsertRange(queenMoves.Count(), generateRookMoves(board, queenLocation, color, kingLocation));
            queenMoves.InsertRange(queenMoves.Count(), generateBishopMoves(board, queenLocation, color, kingLocation));
            return queenMoves;
        }
        
        static public List<ChessMove> generateKingMoves(ChessBoard board, ChessLocation kingLocation, ChessColor color)
        {
            List<ChessMove> kingMoves = new List<ChessMove>();
            ChessLocation newKingLocation;
            ChessMove move;
            ChessBoard newBoard;
            int x, y;
            //Check all 8 directions
            //Y + 1, X + 0
            x = kingLocation.X;
            y = kingLocation.Y + 1;
            newKingLocation = new ChessLocation(x, y);
            if (y <= 7 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            //Y + 1, X + 1
            x = kingLocation.X + 1;
            y = kingLocation.Y + 1;
            newKingLocation = new ChessLocation(x, y);
            if ( y <= 7 && x <= 7 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            //Y + 0, X + 1
            x = kingLocation.X + 1;
            y = kingLocation.Y;
            newKingLocation = new ChessLocation(x, y);
            if (kingLocation.X + 1 <= 7 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            //Y - 1, X + 1
            x = kingLocation.X + 1;
            y = kingLocation.Y - 1;
            newKingLocation = new ChessLocation(x, y);
            if ( y >= 0 && x <= 7 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            //Y - 1, X + 0
            x = kingLocation.X;
            y = kingLocation.Y - 1;
            newKingLocation = new ChessLocation(x, y);
            if ( y >= 0 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            //Y - 1, X - 1
            x = kingLocation.X - 1;
            y = kingLocation.Y - 1;
            newKingLocation = new ChessLocation(x, y);
            if ( y >= 0 && x >= 0 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            //Y + 0, X - 1 
            x = kingLocation.X - 1;
            y = kingLocation.Y;
            newKingLocation = new ChessLocation(x, y);
            if ( x >= 0 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            //Y + 1, X - 1
            x = kingLocation.X - 1;
            y = kingLocation.Y + 1;
            newKingLocation = new ChessLocation(x, y);
            if ( y <= 7 && x >= 0 && !MoveValidation.SameColor(board[newKingLocation], color))
            {
                move = new ChessMove(kingLocation, newKingLocation);
                newBoard = board.Clone();
                newBoard.MakeMove(move);
                if (!MoveValidation.kingInCheck(newBoard, newKingLocation, color))
                    kingMoves.Add(move);
            }
            
            return kingMoves;
        }

        public static bool isEnemyPiece(ChessPiece piece, ChessColor color)
        {
            if (piece != ChessPiece.Empty)
            {
                if (piece < ChessPiece.Empty)
                {
                    //piece is black
                    if (color == ChessColor.Black) return false;
                    else return true;
                }
                if (piece > ChessPiece.Empty)
                {
                    //piece is white
                    if (color == ChessColor.White) return false;
                    else return true;
                }
            }
            return false;
        }

    }//End class MoveGeneration    
}
